<?php


namespace seecms\wechat\controller;

use EasyWeChat\Kernel\Exceptions\HttpException;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use GuzzleHttp\Exception\GuzzleException;
use seecms\controller\SeeBaseController;
use seecms\db\SeeDbException;
use seecms\db\SeeDbQuery;
use seecms\lib\Auth;
use seecms\lib\builder\PageParse;
use seecms\lib\builder\query\SelectQuery;
use seecms\lib\Operate;
use seecms\lib\Transfer;
use seecms\See;
use seecms\SeeException;
use seecms\SeeLang;
use seecms\wechat\config\WechatConfig;
use seecms\wechat\lib\WechatOfficialAccount;
use seecms\wechat\lib\WechatTransfer;

class Wechat extends SeeBaseController
{
    /**
     * @var SeeDbQuery|null
     */
    protected $db = null;

    protected function init()
    {
        $this->db = See::db()->table('see_wechat_material');
    }

    /**
     * @rule_title 微信设置
     * @return string
     * @throws SeeDbException
     */
    public function index(): string
    {
        $setting = See::table()->setting->where('group', 'wechat')->column('value', 'name');

        $lang = SeeLang::instance()->global('wechat');

        return $this->view('wechat/index', [
            'lang' => $lang,
            'setting' => $setting,
            'material_type' => WechatTransfer::wechatMaterialType(),
            'query' => (new PageParse(SeeLang::instance()->global('wechat')))
                ->query(
                    [
                        'filename',
                        SelectQuery::init('type')->setOptions(WechatTransfer::wechatMaterialType()),
                        'created_at'
                    ]
                ),
        ]);
    }

    /**
     * @rule_title 素材库
     */
    public function materialList(): array
    {
        $where = Transfer::pageQuery(['filename', 'type', 'created_at'], See::request()->get());
        $data = $this->db->where($where)->order('id desc')->paginate();

        return $this->success($data);
    }

    /**
     * 保存消息中包含链接或者其他字符，所以不能使用json保存，使用serialize
     * @rule_title 微信公众号设置
     * @return array
     */
    public function saveConfig(): array
    {
        $group = 'wechat';
        $setting = See::request()->post('setting');

        if (empty($setting) || !is_array($setting)) {
            return $this->fail(Operate::isArray('setting'));
        }

        See::provider()->general->save($group, $setting);

        return $this->saveSuccess();
    }

    /**
     * 素材预览
     * @rule_title 素材预览
     */
    public function materialPreview()
    {
        $id = See::request()->param('id');

        $data = $this->db->find($id);
        if (empty($data)) {
            echo 'No material information available';
        } else {
            $root = WechatConfig::materialRoot();
            $filepath = $root . DIRECTORY_SEPARATOR . $data['type'] . DIRECTORY_SEPARATOR . $data['filename'];
            if (is_file($filepath)) {
                header('Content-Type: ' . $data['mime']);
                readfile($filepath);
            } else {
                echo 'The material file does not exist';
            }
        }
        exit();
    }

    /**
     * 素材删除
     * @rule_title 素材删除
     */
    public function materialRemove(): array
    {
        $id = See::request()->post('id');

        $data = See::db()->table('wechat_material')->find($id);

        if (empty($data)) {
            return $this->fail(Operate::notFoundData());
        }

        $expire_time = $data['expire_time'];

        if ($expire_time) {
            return $this->fail('Temporary materials do not need to be deleted');
        }

        try {

            WechatOfficialAccount::app()->material->delete($data['media_id']);

            $this->db->delete($id);

        } catch (InvalidConfigException|GuzzleException$exception) {

        }

        return $this->success(true, Operate::delSuccess());
    }

    /**
     * @rule_title 重置微信公众号菜单
     * @return array
     * @throws SeeException
     */
    public function resetMenu(): array
    {
        $wechat = See::provider()->general->wechat;

        try {

            $menus = $wechat['menu'];
            if (is_string($menus)) {
                $menus = json_decode($menus, true);
            }

            $result = WechatOfficialAccount::app()->menu->create($menus);

            if ($result['errcode']) {
                return $this->fail($result['errmsg']);
            }

        } catch (GuzzleException|InvalidConfigException|HttpException $exception) {
            return $this->fail($exception->getMessage());
        }

        return $this->success(true, __('wechat.reset_wechat_menu_successful'));
    }

    /**
     * @rule_title 上传素材
     * @throws SeeException
     * @throws SeeDbException
     */
    public function uploadMaterial(): array
    {
        $long = See::request()->post('long');
        $type = See::request()->post('type');
        $remark = See::request()->post('remark');

        $root = WechatConfig::materialRoot();
        $url = WechatConfig::materialUrl();
        if (empty($root)) {
            return $this->fail('Please add in the configuration file : wechat.material.root');
        }
        if (empty($url)) {
            return $this->fail('Please add in the configuration file : wechat.material.url');
        }
        $url = '/' . $url . '/' . $type;

        $save_path = ck_directory($root, $type);

        $concat = function ($size, $ext) {
            return compact('size', 'ext');
        };

        $validate = [
            'image' => $concat(10485760, ['bmp', 'png', 'jpeg', 'jpg', 'gif']),
            'thumb' => $concat(65536, ['jpg']),
            'voice' => $concat(2097152, ['mp3', 'wma', 'wav', 'amr']),
            'video' => $concat(10485760, ['mp4']),
        ];

        $file = $_FILES['file'];
        $filename = $file['name'];
        $mime = $file['type'];
        $size = $file['size'];
        $ext = pathinfo($filename, PATHINFO_EXTENSION);

        $valid = $validate[$type] ?? null;
        if (empty($valid)) {
            return $this->fail(SeeLang::wechat('material_type_error'));
        }

        if ($size > $valid['size']) {
            return $this->fail(SeeLang::upload('error_size'));
        }

        if (!in_array($ext, $valid['ext'])) {
            return $this->fail(SeeLang::upload('error_filetype'));
        }

        if (empty($file['tmp_name'])) {
            return $this->fail(SeeLang::upload('error_ini'));
        }

        $save_path = $save_path . '/' . $filename;

        try {

            $app = WechatOfficialAccount::app();

            $class = $long ? $app->material : $app->media;
            $move_result = move_uploaded_file($file['tmp_name'], $save_path);

            if ($move_result) {
                if ($type === 'image') {
                    $result = $class->uploadImage($save_path);
                } elseif ($type === 'thumb') {
                    $result = $class->uploadThumb($save_path);
                } elseif ($type === 'voice') {
                    $result = $class->uploadVoice($save_path);
                } elseif ($type === 'video') {
                    $title = See::request()->post('video_title');
                    $description = See::request()->post('video_desc');
                    $result = $class->uploadVideo($save_path, $title, $description);
                }


                if ($result['errcode'] ?? '') {
                    return $this->fail($result['errmsg'] ?? 'An error occurred');
                }
            }
        } catch (\Exception|GuzzleException $exception) {
            return $this->fail($exception->getMessage());
        }

        if (isset($result['media_id'])) {
            $this->db->save(
                [
                    'filename' => $filename,
                    'filepath' => $url . '/' . $filename,
                    'mime' => $mime,
                    'ext' => $ext,
                    'size' => $size,
                    'type' => $type,
                    'media_id' => $result['media_id'],
                    'url' => $result['url'] ?? '',
                    'expire_time' => $long ? null : date('Y-m-d H:i:s', strtotime('+3 day')),
                    'remark' => $remark
                ]
            );
        }

        return $this->saveSuccess('success');
    }

    public function wechatBind()
    {
        try {
            $qrcode = WechatOfficialAccount::app()->qrcode;
            $flag = 'bind_' . Auth::user()->uuid() . '_' . md5(uniqid());
            $result = $qrcode->temporary($flag, 600);
            $data['ticket'] = $qrcode->url($result['ticket']);
        } catch (\Exception|SeeException $exception) {
            return $this->fail($exception->getMessage());
        }

        return $this->success($data);
    }
}